package repository

import (
	"errors"
	"fmt"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEntity"
	"gitee.com/fierce_wolf/go-fox-edge-common/commEntityManager"
	"gitee.com/fierce_wolf/go-fox-edge-common/commRedisService"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Map"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Method"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Sort"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/String"
	"gitee.com/fierce_wolf/go-fox-edge-common/edgeEntity"
	"strings"
)

type repoLocalDevTemplateService struct {
}

func (e *repoLocalDevTemplateService) SelectEntityList(body map[string]interface{}) []commEntity.IEntity {
	return commEntityManager.FindEntityList(edgeEntity.Type.DeviceTemplateEntity.Type(), func(value commEntity.IEntity) bool {
		entity := value.(*edgeEntity.DeviceTemplateEntity)

		result := true

		if Map.Has(body, "deviceType") {
			result = result && strings.Contains(entity.DeviceType, body["deviceType"].(string))
		}
		if Map.Has(body, "manufacturer") {
			result = result && entity.Manufacturer == body["manufacturer"]
		}
		if Map.Has(body, "subsetName") {
			result = result && entity.SubsetName == body["subsetName"]
		}
		if Map.Has(body, "templateType") {
			result = result && entity.TemplateType == body["templateType"]
		}
		if Map.Has(body, "templateName") {
			result = result && entity.TemplateName == body["templateName"]
		}

		return result
	})
}

func (e *repoLocalDevTemplateService) GetDevTemplateEntityListWithTemplateType(compEntity *edgeEntity.RepoCompEntity, templateType string) []commEntity.IEntity {
	return commEntityManager.FindEntityList(edgeEntity.Type.DeviceTemplateEntity.Type(), func(value commEntity.IEntity) bool {
		entity := value.(*edgeEntity.DeviceTemplateEntity)

		manufacturer := Map.GetString(compEntity.CompParam, "manufacturer", "")
		deviceType := Map.GetString(compEntity.CompParam, "deviceType", "")
		subsetName := Map.GetString(compEntity.CompParam, "subsetName", "")

		if entity.TemplateType != templateType {
			return false
		}
		if entity.Manufacturer != manufacturer {
			return false
		}
		if entity.DeviceType != deviceType {
			return false
		}

		return entity.SubsetName == subsetName
	})
}

func (e *repoLocalDevTemplateService) getDevTemplateChannelList(compEntity *edgeEntity.RepoCompEntity, channelType string) []commEntity.IEntity {
	return commEntityManager.FindEntityList(edgeEntity.Type.DeviceTemplateEntity.Type(), func(value commEntity.IEntity) bool {
		entity := value.(*edgeEntity.DeviceTemplateEntity)

		manufacturer := Map.GetString(compEntity.CompParam, "manufacturer", "")
		deviceType := Map.GetString(compEntity.CompParam, "deviceType", "")
		subsetName := Map.GetString(compEntity.CompParam, "subsetName", "")

		if entity.Manufacturer != manufacturer {
			return false
		}
		if entity.DeviceType != deviceType {
			return false
		}
		if entity.SubsetName != subsetName {
			return false
		}

		return channelType == entity.TemplateParam["channelType"]
	})
}

func (e *repoLocalDevTemplateService) GetDevTemplateEntityList(manufacturer, deviceType, subsetName string) []commEntity.IEntity {
	return commEntityManager.FindEntityList(edgeEntity.Type.DeviceTemplateEntity.Type(), func(value commEntity.IEntity) bool {
		entity := value.(*edgeEntity.DeviceTemplateEntity)

		if entity.Manufacturer != manufacturer {
			return false
		}
		if entity.DeviceType != deviceType {
			return false
		}

		return entity.SubsetName == subsetName
	})
}

func (e *repoLocalDevTemplateService) InsertOrUpdate(params map[string]interface{}) error {
	// 提取业务参数
	compId := Map.GetInt64(params, "compId", 0)
	templateName := Map.GetString(params, "templateName", "")
	templateType := Map.GetString(params, "templateType", "")
	templateParam := Map.GetMap(params, "templateParam", nil)
	extendParam := Map.GetMap(params, "extendParam", nil)

	// 简单校验参数
	if Method.HasNull(params, "compId") || Method.HasEmpty(templateType, templateName) {
		return errors.New("参数不能为空: compId, templateType, templateName")
	}

	exist := commRedisService.GetEntityById(edgeEntity.Type.RepoCompEntity.Type(), compId)
	if exist == nil {
		return errors.New("找不到对应的组件" + String.ToString(compId))
	}
	compEntity := exist.(*edgeEntity.RepoCompEntity)

	manufacturer := Map.GetString(compEntity.CompParam, "manufacturer", "")
	deviceType := Map.GetString(compEntity.CompParam, "deviceType", "")
	subsetName := Map.GetString(compEntity.CompParam, "subsetName", "")
	if Method.HasEmpty(manufacturer, deviceType, subsetName) {
		return errors.New("参数不能为空: manufacturer, deviceType, subsetName")
	}

	// 构造作为参数的实体
	if templateType != "device-param" && templateType != "operate-param" && templateType != "channel-param" {
		return errors.New("类型不正确")
	}
	if templateType == "device-param" && !Map.Has(params, "id") && len(e.GetDevTemplateEntityListWithTemplateType(compEntity, templateType)) > 0 {
		return errors.New("设备参数在同一个子集中，最多只能创建一个")
	}
	if templateType == "channel-param" && !Map.Has(params, "id") && len(e.getDevTemplateChannelList(compEntity, Map.GetString(templateParam, "channelType", ""))) > 0 {
		return errors.New("同一个通道类型的通道参数在同一个子集中，最多只能创建一个")
	}
	if templateType == "operate-param" && e.verifyOperateParam(templateParam) != nil {
		return errors.New("操作参数的格式不合法")
	}

	entity := edgeEntity.Type.DeviceTemplateEntity.Instance()
	entity.Manufacturer = manufacturer
	entity.DeviceType = deviceType
	entity.SubsetName = subsetName
	entity.TemplateType = templateType
	entity.TemplateName = templateName
	entity.TemplateParam = templateParam
	entity.ExtendParam = extendParam

	// 新增/修改实体：参数不包含id为新增，包含为修改
	if !Map.Has(params, "id") {
		if entity.TemplateParam == nil {
			entity.TemplateParam = make(map[string]interface{})
		}
		if entity.ExtendParam == nil {
			entity.ExtendParam = make(map[string]interface{})
		}

		exist, err := commEntityManager.GetEntityByServiceKey(entity.Type(), entity.MakeServiceKey())
		if err != nil {
			return err
		}
		if exist != nil {
			return errors.New("实体已存在")
		}

		err = commEntityManager.InsertEntity(entity)
		if err != nil {
			return err
		}

		return nil
	} else {
		id := Map.GetInt64(params, "id", 0)

		exist := commEntityManager.GetEntityById(entity.Type(), id)
		if exist == nil {
			return errors.New("实体不存在")
		}
		deviceTemplateEntity := exist.(*edgeEntity.DeviceTemplateEntity)

		// 如果没有填写，说明只是修改标题，那么填入原来的数值
		if Method.HasEmpty(entity.TemplateParam) {
			entity.TemplateParam = deviceTemplateEntity.TemplateParam
		}
		// 如果为空，那么说明用户不想修改该数据
		if entity.ExtendParam == nil {
			entity.ExtendParam = deviceTemplateEntity.ExtendParam
		}

		if deviceTemplateEntity.Manufacturer != manufacturer || deviceTemplateEntity.DeviceType != deviceType || deviceTemplateEntity.SubsetName != subsetName || deviceTemplateEntity.TemplateType != templateType || deviceTemplateEntity.TemplateName != templateName {
			return errors.New("不允许修改，否则影响关联关系：manufacturer, deviceType, subsetName, templateType, templateName")
		}

		// 修改数据
		entity.BaseEntity.Id = id
		entity.GetBaseEntity().CreateTime = exist.GetBaseEntity().CreateTime
		entity.GetBaseEntity().UpdateTime = exist.GetBaseEntity().UpdateTime
		return commEntityManager.UpdateEntity(entity)
	}
}

func (e *repoLocalDevTemplateService) verifyOperateParam(templateParam map[string]interface{}) (err error) {
	// 定义一个最终的异常拦截，用来防止可能的代码BUG
	defer func() {
		if r := recover(); r != nil {
			message := fmt.Sprintf("repoLocalDevTemplateService.verifyOperateParam() 捕获到异常:%v", r)
			err = errors.New(message)
		}
	}()

	// 参数检测：通过强制转换，检测是否会发生panic，然后被上面的defer捕获
	param := Map.GetMap(templateParam, "param", nil)
	operateMode := Map.GetString(templateParam, "operateMode", "")
	operateName := Map.GetString(templateParam, "operateName", "")
	timeout := Map.GetInt(templateParam, "timeout", 0)

	if Method.HasEmpty(operateName, operateMode) {
		return errors.New("参数不能为空：operateName, operateMode")
	}
	if param == nil || timeout == 0 {
		return errors.New("参数不能为空：param, timeout")
	}

	return nil
}

func (e *repoLocalDevTemplateService) DeleteEntity(id int64) {
	entity := commEntityManager.GetEntityById(edgeEntity.Type.DeviceTemplateEntity.Type(), id)
	if entity == nil {
		return
	}

	err := commEntityManager.DeleteEntity(entity)
	if err != nil {
		return
	}
}

func (e *repoLocalDevTemplateService) QueryEntity(id int64) *edgeEntity.DeviceTemplateEntity {
	exist := commEntityManager.GetEntityById(edgeEntity.Type.DeviceTemplateEntity.Type(), id)
	if exist == nil {
		return nil
	}

	return exist.(*edgeEntity.DeviceTemplateEntity)
}

func (e *repoLocalDevTemplateService) getCompEntity(manufacturer, deviceType, subsetName string) *edgeEntity.RepoCompEntity {
	exist := commEntityManager.FindEntity(edgeEntity.Type.RepoCompEntity.Type(), func(value commEntity.IEntity) bool {
		entity := value.(*edgeEntity.RepoCompEntity)

		if "device-template" != entity.CompType {
			return false
		}
		if manufacturer != Map.GetString(entity.CompParam, "manufacturer", "") {
			return false
		}
		if deviceType != Map.GetString(entity.CompParam, "deviceType", "") {
			return false
		}
		if subsetName != Map.GetString(entity.CompParam, "subsetName", "") {
			return false
		}

		return true
	})

	if exist == nil {
		return nil
	}

	return exist.(*edgeEntity.RepoCompEntity)
}

func (e *repoLocalDevTemplateService) SelectOptionList(body map[string]interface{}) ([]map[string]interface{}, error) {
	field := Map.GetString(body, "field", "")
	manufacturer := Map.GetString(body, "manufacturer", "")
	deviceType := Map.GetString(body, "deviceType", "")
	templateType := Map.GetString(body, "templateType", "")
	subsetName := Map.GetString(body, "subsetName", "")
	operateName := Map.GetString(body, "operateName", "")
	channelType := Map.GetString(body, "channelType", "")

	if Method.HasEmpty(field, manufacturer, deviceType, templateType) {
		return nil, errors.New("参数缺失：field, manufacturer, deviceType, templateType")
	}

	values := make(map[string]interface{})
	commEntityManager.FindEntityList(edgeEntity.Type.DeviceTemplateEntity.Type(), func(value commEntity.IEntity) bool {
		entity := value.(*edgeEntity.DeviceTemplateEntity)

		if templateType != entity.TemplateType {
			return false
		}
		if manufacturer != entity.Manufacturer {
			return false
		}
		if deviceType != entity.DeviceType {
			return false
		}

		// 场景1：创建设备时，下拉设备类型列表，会传递这两个参数
		if field == "subsetName" && templateType == "device-param" {
			values[entity.SubsetName] = entity.SubsetName
			return false
		}
		// 场景2：创建操作任务时，下拉设备类型列表，会传递这两个参数
		if field == "subsetName" && templateType == "operate-param" {
			if Method.HasEmpty(operateName) {
				return false
			}
			if operateName != entity.TemplateParam["operateName"] {
				return false
			}

			if Map.Has(values, entity.SubsetName) {
				return false
			}

			values[entity.SubsetName] = entity.SubsetName
			return false
		}

		// 场景3：创建操作任务时，下拉子集列表，会传递这两个参数
		if field == "templateName" && templateType == "operate-param" {
			if entity.SubsetName != subsetName {
				return false
			}
			if Method.HasEmpty(operateName) {
				return false
			}
			if operateName != entity.TemplateParam["operateName"] {
				return false
			}

			values[entity.TemplateName] = entity.TemplateName
			return false
		}

		// 场景4：创建通道时，下拉子集列表，会传递这两个参数
		if field == "templateName" && templateType == "channel-param" {
			if entity.SubsetName != subsetName {
				return false
			}
			if Method.HasEmpty(channelType) {
				return false
			}
			if channelType != entity.TemplateParam["channelType"] {
				return false
			}

			values[entity.TemplateName] = entity.TemplateName
			return false
		}

		return false
	})

	resultList := make([]map[string]interface{}, 0)
	for key, _ := range values {
		option := make(map[string]interface{})
		option["value"] = key
		option["label"] = key

		resultList = append(resultList, option)
	}

	return resultList, nil
}

func (e *repoLocalDevTemplateService) SelectGroupList(body map[string]interface{}) []map[string]interface{} {
	manufacturer := Map.GetString(body, "manufacturer", "")
	deviceType := Map.GetString(body, "deviceType", "")
	subsetName := Map.GetString(body, "subsetName", "")

	sums := make(map[string]int)
	sums["operate-param"] = 0
	sums["device-param"] = 0
	sums["channel-param"] = 0

	commEntityManager.FindEntityList(edgeEntity.Type.DeviceTemplateEntity.Type(), func(value commEntity.IEntity) bool {
		entity := value.(*edgeEntity.DeviceTemplateEntity)

		if manufacturer != entity.Manufacturer {
			return false
		}
		if deviceType != entity.DeviceType {
			return false
		}
		if subsetName != entity.SubsetName {
			return false
		}

		val, ok := sums[entity.TemplateType]
		if ok {
			sums[entity.TemplateType] = val + 1
		}
		return false
	})

	resultList := make([]map[string]interface{}, 0)
	for k, v := range sums {
		data := make(map[string]interface{})
		data["templateType"] = k
		data["count"] = v

		data["manufacturer"] = manufacturer
		data["deviceType"] = deviceType
		data["subsetName"] = subsetName

		resultList = append(resultList, data)
	}

	Sort.Sort(resultList, func(entity1, entity2 interface{}) bool {
		id1 := entity1.(map[string]interface{})["templateType"].(string)
		id2 := entity2.(map[string]interface{})["templateType"].(string)
		return id1 > id2
	})

	return resultList
}
